package com.atom.module.coroutine.core

import android.annotation.SuppressLint
import com.atom.module.coroutine.context.CoroutineName
import com.atom.module.coroutine.cancel.suspendCancellableCoroutine
import com.atom.module.coroutine.scope.CoroutineScope
import com.atom.module.coroutine.utils.log
import java.lang.Exception
import java.util.concurrent.atomic.AtomicReference
import kotlin.coroutines.Continuation
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
import kotlin.coroutines.resume

// 一个抽象的 协程对象 , 主要包含所在的协程作用域
// 实现Job 可挂起 可取消 可完成 可加入
// 实现协程作用域, 可以有子协程
abstract class AbstractCoroutine<T> : Job, Continuation<T>,
    CoroutineScope {

    protected val state: AtomicReference<CoroutineState> = AtomicReference<CoroutineState>()

    override val context: CoroutineContext

    override val scopeContext: CoroutineContext
        get() = context

    protected val parentJob: Job?

    private var parentCancelDisposable: Disposable? = null

    val isCompleted // 是否完成
        get() = state.get() is CoroutineState.Complete<*>

    override val isActive: Boolean // 是否活动的
        get() = when (val currentState = state.get()) {
            is CoroutineState.Complete<*>, // 完成 不活动
            is CoroutineState.Cancelling -> false // 取消中 不活动
            is CoroutineState.CompleteWaitForChildren<*> -> !currentState.isCancelling // 等待子任务 , 判断子任务 子类活动 返回活动
            is CoroutineState.InComplete -> true // 未完成的 活动
        }

    constructor(context: CoroutineContext) {
        // 从父类环境 获取Job-key 对应的 Job 对象
        this.parentJob = context[Job]
        // 设置状态为 未完成态
        this.state.set(CoroutineState.InComplete())
        // 创建一个 协程环境 间其 再原基础上 加上一个
        this.context = context + this
        // 根据父Job 得到子类的 Disposable
        this.parentCancelDisposable = parentJob?.attachChild(this)
    }

    @SuppressLint("NewApi")
    override fun resumeWith(result: Result<T>) {
        val newState = state.updateAndGet { prevState ->
            when (prevState) {
                //虽然取消了，但作业流可能会以正常结果运行。
                is CoroutineState.Cancelling, // 正在取消 尝试完成
                is CoroutineState.InComplete -> prevState.tryComplete(result) // 未完成 尝试完成
                is CoroutineState.CompleteWaitForChildren<*>,  // 等待子类
                is CoroutineState.Complete<*> -> { // 完成
                    throw IllegalStateException("Already completed!")
                }
            }
        }
        when (newState) {
            is CoroutineState.CompleteWaitForChildren<*> -> newState.tryWaitForChildren(::tryCompleteOnChildCompleted)
            is CoroutineState.Complete<*> -> makeCompletion(newState as CoroutineState.Complete<T>)
        }
    }

    @SuppressLint("NewApi")
    private fun tryCompleteOnChildCompleted(child: Job) {
        // 尝试完成 判断状态
        val newState = state.updateAndGet { prev ->
            when (prev) {
                is CoroutineState.Cancelling, // 取消中
                is CoroutineState.InComplete -> { // 未完成
                    throw IllegalStateException("Should be waiting for children!")
                }
                is CoroutineState.CompleteWaitForChildren<*> -> { // 去等待子类的完成
                    prev.onChildCompleted(child) // 如果子类完成
                }
                is CoroutineState.Complete<*> -> throw IllegalStateException("Already completed!")
            }
        }
        // 如果状态为 子类完成态 完成态
        (newState as? CoroutineState.Complete<T>)?.let {
            // 进行完成操作
            makeCompletion(it)
        }
    }

    private fun makeCompletion(newState: CoroutineState.Complete<T>) {
        val result = if (newState.exception == null) {
            // 设置完成成功
            Result.success(newState.value)
        } else {
            // 设置完成失败
            Result.failure<T>(newState.exception)
        }
        // 交给父类 处理
        result.exceptionOrNull()?.let(this::tryHandleException)
        // 进行通知完成
        newState.notifyCompletion(result)
        // 清除自生
        newState.clear()
        // 父类的取消处理器进行分发
        parentCancelDisposable?.dispose()
    }

    // 进行执行
    override suspend fun join() {
        when (state.get()) {
            is CoroutineState.InComplete,
            is CoroutineState.CompleteWaitForChildren<*>,
            is CoroutineState.Cancelling -> return joinSuspend()
            is CoroutineState.Complete<*> -> {
                // 判断当前的活动状态
                val currentCallingJobState = coroutineContext[Job]?.isActive ?: return
                // 判断当前的状态 false 为 死机状态
                if (!currentCallingJobState) {
                    throw CancellationException("Coroutine is cancelled.")
                }
                return
            }
        }
    }

    private suspend fun joinSuspend() = suspendCancellableCoroutine<Unit>(block = { continuation ->
        val disposable = doOnCompleted(block = { result ->
            continuation.resume(Unit)
        })
        continuation.invokeOnCancellation(onCancel = { ->
            disposable.dispose()
        })
    })

    @SuppressLint("NewApi")
    override fun cancel() {
        // 判断状态
        val prevState = state.getAndUpdate { prev ->
            when (prev) {
                // 判断此时为未完成态
                is CoroutineState.InComplete -> {
                    // 返回一个正在取消的状态,并拷贝
                    CoroutineState.Cancelling().from(prev)
                }
                is CoroutineState.Cancelling, // 判断正在取消 返回已完成态
                is CoroutineState.Complete<*> -> prev // 如果时已完成,返回已完成态
                is CoroutineState.CompleteWaitForChildren<*> -> {
                    // 判断为等待子任务完成 , 进行自我拷贝,并设置子类的为取消标识 为 true
                    prev.copy(isCancelling = true)
                }
            }
        }
        // 判断返回的状态为 未完成态 进行通知
        if (prevState is CoroutineState.InComplete) {
            // 进行通知 自我的取消
            prevState.notifyCancellation()
        }
        // 进行通知
        parentCancelDisposable?.dispose()
    }

    @SuppressLint("NewApi")
    protected fun doOnCompleted(block: (Result<T>) -> Unit): Disposable {
        // 创建一个一次性完成处理器
        val disposable = CompletionHandlerDisposable(this, block)
        val newState = state.updateAndGet { prev ->
            when (prev) {
                // 判断 未完成的
                is CoroutineState.InComplete -> {
                    // 新建一个未完成状态, 并且设置一个完成处理器的监听
                    CoroutineState.InComplete().from(prev).with(disposable)
                }
                is CoroutineState.Cancelling -> {
                    // 新建一个未完成状态, 并且设置一个完成处理器的监听
                    CoroutineState.Cancelling().from(prev).with(disposable)
                }
                is CoroutineState.Complete<*> -> {
                    // 完成态 不做修改直接返回
                    prev
                }
                // 判断为等待子任务完成态 自我复制并设置
                is CoroutineState.CompleteWaitForChildren<*> -> prev.copy().with(disposable)
            }
        }
        (newState as? CoroutineState.Complete<T>)?.let {
            block( // 如果是完成态 进行回调result
                when {
                    it.exception != null -> Result.failure(it.exception)
                    it.value != null -> Result.success(it.value)
                    else -> throw IllegalStateException("Won't happen.")
                }
            )
        }
        return disposable
    }

    @SuppressLint("NewApi")
    override fun invokeOnCancel(onCancel: OnCancel): Disposable {
        // 创建一个取消的执行器
        val disposable = CancellationHandlerDisposable(this, onCancel)
        val newState = state.updateAndGet { prev ->
            when (prev) {
                is CoroutineState.InComplete -> {
                    CoroutineState.InComplete().from(prev).with(disposable)
                }
                is CoroutineState.Cancelling,
                is CoroutineState.Complete<*> -> {
                    prev
                }
                is CoroutineState.CompleteWaitForChildren<*> -> prev.copy().with(disposable)
            }
        }
        (newState as? CoroutineState.Cancelling)?.let {
            // call immediately when Cancelling.
            // 判断为正在取消态 立即执行取消
            onCancel()
        }
        return disposable
    }

    override fun invokeOnCompletion(onComplete: OnComplete): Disposable {
        return doOnCompleted { result ->
            onComplete()
        }
    }

    @SuppressLint("NewApi")
    override fun remove(disposable: Disposable) {
        // 移除
        state.updateAndGet { prev ->
            when (prev) {
                is CoroutineState.InComplete -> {
                    CoroutineState.InComplete().from(prev).without(disposable)
                }
                is CoroutineState.Cancelling -> {
                    CoroutineState.Cancelling().from(prev).without(disposable)
                }
                is CoroutineState.Complete<*> -> {
                    prev
                }
                is CoroutineState.CompleteWaitForChildren<*> -> prev.copy().without(disposable)
            }
        }
    }

    // 进行处理异常
    private fun tryHandleException(e: Throwable): Boolean {
        return when (e) {
            // 判断时
            is CancellationException -> {
                false
            }
            else -> {
                // 判断父亲是否继承 AbstractCoroutine , 如果是 及逆行处理
                (parentJob as? AbstractCoroutine<*>)?.handleChildException(e)?.takeIf { it -> it }
                    ?: handleJobException(e)
            }
        }
    }

    // 进行处理异常
    protected open fun handleChildException(e: Throwable): Boolean {
        // 子任务出现异常 父任务进行取消操作
        cancel()
        // 再次通知上层进行操作
        return tryHandleException(e)
    }

    protected open fun handleJobException(e: Throwable) = false

    @SuppressLint("NewApi")
    override fun attachChild(child: Job): Disposable {
        // 判断状态
        state.updateAndGet { prev ->
            when (prev) {
                is CoroutineState.InComplete -> {
                    // 获取当前的状态并进行复制,后 将 job 添加进去
                    CoroutineState.InComplete().from(prev).with(child)
                }
                is CoroutineState.Cancelling -> {
                    CoroutineState.Cancelling().from(prev).with(child)
                }
                is CoroutineState.CompleteWaitForChildren<*> -> prev.copy().with(child)
                is CoroutineState.Complete<*> -> throw IllegalStateException("Parent already completed.")
            }
        }
        // 进行执行取消操作 并返回使用 Disposable 包装的job
        return invokeOnCancel {
            child.cancel()
        }
    }

    override fun toString(): String {
        return context[CoroutineName].toString()
    }
}

